package com.upeng.commons.net;

import java.io.BufferedReader;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;
import java.util.Map;

import com.upeng.commons.lang.BytesUtils;
import com.upeng.commons.lang.Charsets;
import com.upeng.commons.lang.time.StopWatch;

/**
 * <p>Execute simple HTTP request, support Get、Post&Head Method</p>
 * <p>Once you need manage cookie, you should use HttpClient, not this Class</p>
 * @author Lucky
 *
 */
public class HttpRequestUtils {
	
	//default time out setting , half minute
	private static final int defaultTimeOut = 30*1000;
	
	private static final String defaultCharset = Charsets.UTF_8;
	
	private static void validateUrl(String url){
		if(!URLUtils.isUseHttpProtocol(url)){
			throw new java.lang.IllegalArgumentException(String.format("The URL %s is illegal", url));
		}
	}
	
	/**
	 * <p>Do HTTP GET Request</p>
	 * @param url the HTTP URL for Request
	 * @param charSetName char set name etc. UTF_8,GB3212
	 * @param timeOut time out setting
	 * @return response stream
	 * @throws RequestException
	 */
	public static String doGet(String url, String charSetName, int timeOut) throws RequestException{
		validateUrl(url);
		try{
			URL ur = new URL(url);
			URLConnection con = ur.openConnection();
			con.setConnectTimeout(timeOut);
			con.setReadTimeout(timeOut);
			BufferedReader rd = new BufferedReader(new InputStreamReader(con.getInputStream(),charSetName));
			StringBuilder sb = new StringBuilder();
			try{			
				int k = rd.read();
				while(k!=-1){
					sb.append((char)k);
					k = rd.read();				
				}			
			}catch(Exception ee){
			}finally{
				if(rd != null){
					rd.close();
				}
			}
			return sb.toString();	
		}catch(Exception e){
			throw new RequestException(e);
		}
	}
	
	/**
	 * <p>Do HTTP GET Request, user default timeout setting</p>
	 * @param url the HTTP URL for Request
	 * @param charSetName char set name etc. UTF_8,GB3212
	 * @return response stream
	 * @throws RequestException
	 */
	public static String doGet(String url, String charSetName) throws RequestException{
		return doGet(url, charSetName, defaultTimeOut);
	}
	
	/**
	 * <p>Do HTTP GET Request, use default timeout setting & charSetName</p>
	 * @param url the HTTP URL for Request
	 * @return response stream
	 * @throws RequestException
	 */
	public static String doGet(String url) throws RequestException{
		return doGet(url,defaultCharset,defaultTimeOut);
	}
	
	/**
	 * <p>Get file From remote URL and store in disk</p>
	 * @param url the HTTP URL for Request
	 * @param timeOut time out setting
	 * @param fullFileName ect. c:/a.jar
	 * @throws RequestException
	 */
	public static void doGetFile(String url, int timeOut, String fullFileName) throws RequestException{
		validateUrl(url);
		InputStream is = null;
		OutputStream os = null;
		try{
			URL ur = new URL(url);
			URLConnection con = ur.openConnection();
			con.setConnectTimeout(timeOut);
			con.setReadTimeout(timeOut);		
			      
		    is = con.getInputStream();        
		       
		    // 1K cache     
		    byte[] bs = new byte[1024];        
		    // length      
		    int len; 
		    
		    os = new FileOutputStream(fullFileName);                
		    while ((len = is.read(bs)) != -1) {        
		      os.write(bs, 0, len);        
		    }            
		}catch(Exception e){
			throw new RequestException(e);
		}finally{
			if(os != null){
				try {
					os.close();
				} catch (IOException e) {
				}
			}
			if(is != null){
				try {
					is.close();
				} catch (IOException e) {
				}
			}
		}
	}
	
	/**
	 * <p>Get InputStream from URL</p>
	 * @param url the HTTP URL for Request
	 * @param timeOut time out setting
	 * @return response stream
	 * @throws RequestException
	 */
	public static InputStream doGetStream(String url, int timeOut) throws RequestException{
		validateUrl(url);
		InputStream is = null;
		try{
			URL ur = new URL(url);
			URLConnection con = ur.openConnection();
			con.setConnectTimeout(timeOut);
			con.setReadTimeout(timeOut);					      
		    is = con.getInputStream();     
		    return is;
		}catch(Exception e){
			throw new RequestException(e);
		}finally{
			if(is != null){
				try {
					is.close();
				} catch (Exception unusede) {
				}
			}
		}
	}
	
	/**
	 * <p>Do HTTP POST request</p>
	 * @param url the HTTP URL for Request
	 * @param parameters the posting parameter
	 * @param timeOut Timeout Setting
	 * @param charSetName char set name etc. UTF_8,GB3212
	 * @return response stream
	 */
	public static String doPost(String url, Map<String, String> parameters, int timeOut, String charSetName) throws RequestException{
		//validate
		validateUrl(url);
		
		//generate post data form parameters
		StringBuilder sb= new StringBuilder();
		for(Map.Entry<String, String> kv: parameters.entrySet()){
			sb.append(kv.getKey());
			sb.append("=");
			sb.append(URLUtils.decode(kv.getValue()));
			sb.append("&");
		}
		if(sb.length() > 0){
			sb.deleteCharAt(sb.length() - 1);
		}
		byte[] postData = BytesUtils.toBytes(sb);	
		try{
			URL ur = new URL(url);
			URLConnection con = ur.openConnection();
			
			//setting
			con.setConnectTimeout(timeOut);
			con.setReadTimeout(timeOut);			
			con.setDoInput(true);
			con.setDoOutput(true);
			con.setUseCaches(false);
			con.setDefaultUseCaches(false);
			
			con.setRequestProperty("Content-Length", postData.length+"");
			OutputStream os = con.getOutputStream();
			
			os.write(postData);
			os.flush();
			os.close();		
			BufferedReader rd = new BufferedReader(new InputStreamReader(con.getInputStream(),charSetName));
			StringBuilder rsb = new StringBuilder();
			try{			
				int k = rd.read();
				while(k!=-1){
					rsb.append((char)k);
					k = rd.read();				
				}			
			}catch(Exception ee){}
			finally{
				try{
					rd.close();
				}catch(Exception e){
					
				}
			}
			return rsb.toString();	
		}catch(Exception e){
			throw new RequestException(e);
		}
	}
	
	/**
	 * <p>Do HTTP POST request, Use default char set</p>
	 * @param url the HTTP URL for Request
	 * @param parameters the posting parameter
	 * @param timeOut Timeout Setting
	 * @return response stream
	 */
	public static String doPost(String url, Map<String, String> parameters, int timeOut) throws RequestException{
		return HttpRequestUtils.doPost(url, parameters, timeOut, defaultCharset);
	}
	
	/**
	 * <p>Do HTTP POST request, User default time out setting & char set</p>
	 * @param url the HTTP URL for Request
	 * @param parameters the posting parameter
	 * @return response stream
	 */
	public static String doPost(String url, Map<String, String> parameters)  throws RequestException{
		return HttpRequestUtils.doPost(url, parameters, defaultTimeOut, defaultCharset);
	}
	
	/**
	 * <p>Do HTTP HEAD Request</p>
	 * @param url  the HTTP URL for Request
	 * @param timeOut timeout setting
	 * @return state code
	 * @throws RequestException
	 */
	public static int doHead(String url, int timeOut) throws RequestException{
		validateUrl(url);
		try{
			URL ur = new URL(url);
			HttpURLConnection con = (HttpURLConnection)ur.openConnection();
			con.setConnectTimeout(timeOut);		
			return con.getResponseCode();
		}catch(Exception e){
			throw new RequestException(e);
		}
	}
	
	/**
	 * <p>Do HTTP HEAD Request, user default timeout setting</p>
	 * @param url  the HTTP URL for Request
	 * @return state code
	 * @throws RequestException
	 */
	public static int doHead(String url) throws RequestException{
		return doHead(url, defaultTimeOut);
	}	
	
	public static void main(String[] args) throws RequestException{
		StopWatch watch = new StopWatch();
		HttpRequestUtils.doGetFile("http://218.16.122.168:82/Tplfilerar/4/2013-3-13/期末八数学-新方案.rar", 60 * 1000, "D:/test.rar");
		System.out.println(watch.getInterval());
	}
}
